package com.gitee.wsl.net.ssdp.service


import com.gitee.wsl.net.ssdp.device.Device
import com.gitee.wsl.net.ssdp.message.Headers
import com.gitee.wsl.net.ssdp.message.SsdpMessage
import kotlin.uuid.ExperimentalUuidApi
import kotlin.uuid.Uuid

@Suppress("UNUSED_PARAMETER")
class Service @OptIn(ExperimentalUuidApi::class) constructor(
        val location: String,
        val os: String? = null,
        val osVersion: String? = null,
        val upnpVersion: String? = null,
        val productName: String? = null,
        val productVersion: String? = null,
        val uuid: Uuid,
        val uniqueResourceName: String? = null,
        val bootId: Int,
        val nextBootId: Int? = null,
        val configId: Int,
        val searchPort: Int? = null,
        val secureLocation: String? = null,
        val lastAliveTs: Long,
        val lastUpdateTs: Long? = null,
        val lastByeByeTs: Long? = null
){
    @OptIn(ExperimentalUuidApi::class)
    fun getUsn():String = "uuid:$uuid::$uniqueResourceName"

    companion object {
        @OptIn(ExperimentalUuidApi::class)
        fun fromSsdpMessage(msg: SsdpMessage): Device {
            var osData: List<String>? = null
            var upnpData: List<String>? = null
            var productData: List<String>? = null
            msg.getHeader(Headers.Server)?.split(" ")?.let { serverMeta ->
                osData = serverMeta[0].split("/")
                upnpData = serverMeta[1].split("/")
                productData = serverMeta[2].split("/")
            }
            val usn = msg.getRequiredHeader(Headers.UniqueServiceName).split("::")
            if (!usn[0].startsWith("uuid:")) throw IllegalStateException("Invalid USN header '$usn'")
            val uuid = usn[0].substring(5)
            val urn = if (usn.size > 1) usn[1] else null
            val resourceName = msg.getRequiredHeader(Headers.NotificationType)
            if ((urn ?: uuid) != resourceName) throw IllegalStateException("Invalid USN header '$usn'")
            return Device(
                location = msg.getRequiredHeader(Headers.Location),
                os = osData?.get(0),
                osVersion = osData?.get(1),
                upnpVersion = upnpData?.get(1),
                productName = productData?.get(0),
                productVersion = productData?.get(1),
                uuid = Uuid.parse(uuid),
                uniqueResourceName = urn,
                bootId = msg.getRequiredHeader(Headers.BootId).toInt(),
                nextBootId = msg.getHeader(Headers.NextBootId)?.toInt(),
                configId = msg.getRequiredHeader(Headers.ConfigId).toInt(),
                searchPort = msg.getHeader(Headers.SearchPort)?.toInt(),
                secureLocation = msg.getHeader(Headers.SecureLocation),
                lastAliveTs = msg.ts
            )
        }
    }
}